#include "basic_parser.h"

using namespace std;
using namespace eg;

//==================================================================================================
//                            Specific parsers implementation
//==================================================================================================

//eof class
bool eof::parse(bool gen_ast) {
	//push this parser actual rule stack of errors
	the_context->error_rule_stack.top()->error_parsers_stack.push(this);

	return the_context->input.eof();
}

// A given character: E = 'c'
bool a_char_parser::parse(bool gen_ast) {
	// skip blanks treatment
	if (the_context->skip_parser) {
		//push this parser actual rule stack of errors, when isnt a blank parser
		the_context->error_rule_stack.top()->error_parsers_stack.push(this);
		the_context->skip_parser->parse();
	}

	int old_size_of_stack = the_context->s.size();
	pos_type pos = the_context->input.tellg();

	//cout << "trying parsing " << to_string() << " ..." << endl;
	if (the_context->input.eof())
		return false;

	char c;

	the_context->input.get(c);

	//parcial_nl_counter
	if (c == '\n') {
		the_context->parcial_nl_counter++;
	}
	if (c == char_to_match) {
		string node_desc;
		if (gen_ast)
			node_desc = string("'") + c + '\'';
		return true;//accept(node_desc);
	} else
		return reject(pos, the_context->s.size() - old_size_of_stack);
}

// A character class parser: [class]
bool char_class_parser::parse(bool gen_ast) {
	// skip blanks treatment
	if (the_context->skip_parser) {
		//push this parser actual rule stack of errors, when isnt a blank parser
		the_context->error_rule_stack.top()->error_parsers_stack.push(this);
		the_context->skip_parser->parse();
	}

	int old_size_of_stack = the_context->s.size();
	pos_type pos = the_context->input.tellg();

	//cout << "trying parsing " << to_string() << " ..." << endl;
	if (the_context->input.eof())
		return false;

	char c;
	the_context->input.get(c);

	//parcial_nl_counter
	if (c == '\n') {
		the_context->parcial_nl_counter++;
	}

	if (class_to_match.find(c) != string::npos) {
		string node_desc;
		if (gen_ast)
			node_desc = string("'") + c + '\'';
		return true;
	} else
		return reject(pos, the_context->s.size() - old_size_of_stack);
}

// A character range parser: [a-b]
bool char_range_parser::parse(bool gen_ast) {
	// skip blanks treatment
	if (the_context->skip_parser) {
		//push this parser actual rule stack of errors, when isnt a blank parser
		the_context->error_rule_stack.top()->error_parsers_stack.push(this);
		the_context->skip_parser->parse();
	}
	int old_size_of_stack = the_context->s.size();
	pos_type pos = the_context->input.tellg();

	//cout << "trying parsing " << to_string() << " ..." << endl;
	if (the_context->input.eof())
		return false;

	char c;
	the_context->input.get(c);
	//parcial_nl_counter
	if (c == '\n') {
		the_context->parcial_nl_counter++;
	}

	if (c >= a and c <= b) {
		string node_desc;
		if (gen_ast)
			node_desc = string("'") + c + '\'';
		return true;
	} else
		return reject(pos, the_context->s.size() - old_size_of_stack);
}

// A given string: E = "s"
bool a_string_parser::parse(bool gen_ast) {
	// skip blanks treatment
	if (the_context->skip_parser) {
		//push this parser actual rule stack of errors, when isnt a blank parser
		the_context->error_rule_stack.top()->error_parsers_stack.push(this);
		the_context->skip_parser->parse();
	}

	pos_type pos = the_context->input.tellg();
	bool cont = !the_context->input.eof();
	char c;
	string node_desc;
	int old_size_of_stack = the_context->s.size();
	//cout << "trying parsing " << to_string() << " ..." << endl;

	for (unsigned int i = 0; cont and i < string_to_match.length(); i++) {
		the_context->input.get(c);
		//parcial_nl_counter
		if (c == '\n') {
			the_context->parcial_nl_counter++;
		}

		if (c != string_to_match[i])
			cont = false;
		cont &= !the_context->input.eof();
	}
	if (cont) {
		string node_desc;
		if (gen_ast)
			node_desc = string("\"") + string_to_match + '"';
		return true;
	} else
		reject(pos, the_context->s.size() - old_size_of_stack);
	return 0;
}

// Any character (advance): E = .
bool some_char_parser::parse(bool gen_ast) {
	// skip blanks treatment
	if (the_context->skip_parser) {
		//push this parser actual rule stack of errors, when isnt a blank parser
		the_context->error_rule_stack.top()->error_parsers_stack.push(this);
		the_context->skip_parser->parse();
	}
	int old_size_of_stack = the_context->s.size();
	pos_type pos = the_context->input.tellg();
	char c;
	bool r = the_context->input.eof();
	//cout << "trying parsing " << to_string() << " ..." << endl;

	if (!r) {
		the_context->input.get(c);
		//parcial_nl_counter
		if (c == '\n') {
			the_context->parcial_nl_counter++;
		}

	}
	if (r) {
		string node_desc;
		if (gen_ast)
			node_desc = string("'") + c + '\'';
		return true;
	} else
		reject(pos, the_context->s.size() - old_size_of_stack);
	return 0;
}

// error parser
bool error_parser::parse(bool gen_ast) {
	the_context->error_mode_by_mistake = 0; // will be true if error_parser must not be parsing

	cout <<'\n'<< "trying parsing  ERROR PARSER" << " ..." << endl;

	if (the_context->input.eof()) //input must not be eof
		return false;

	char c;
	the_context->input.get(c); //extract an input without format it

	//Loop skipping all characters until recuperation point.
	while ((c != rec_point) && (c != look_ahead) &&(!the_context->input.eof())) {

		if (c == '\n') {		//parcial_nl_counter
			the_context->acum_nl_counter++;
			the_context->parcial_nl_counter = 0;
		}

		the_context->input.get(c);
	}

	// brake the parsing if look ahead is found
	if (c == look_ahead ) {
			the_context->brake_error_parser = 1;
			the_context->error_mode_by_mistake = 1;
			the_context->input.putback(c);
			return true;
		}

	the_context->error_mode = 1; 			// error mode
	if (c == rec_point) {
		int i = 1;
		cout << "line " << the_context->acum_nl_counter + 1 << " error: in "
				<< the_context->error_rule_stack.top()->parser_name()
				<< " rule " << endl;
		/*while (i < 4
						and !the_context->error_rule_stack.empty()){
					string c;
					c.clear();
					c = the_context->error_rule_stack.top()->parser_name();
					cout << " error trying parsing " << c << endl;
					the_context->error_rule_stack.pop();
					i++;
				}*/
		while (i < 4
				and !the_context->error_rule_stack.top()->error_parsers_stack.empty()) {
			string c;
			c.clear();

			c = the_context->error_rule_stack.top()->error_parsers_stack.top()->parser_name();
			cout << " error trying parsing " << c << endl;
			the_context->error_rule_stack.top()->error_parsers_stack.pop();
			i++;
		}
		if (c == '\n') {
						the_context->acum_nl_counter++;
						the_context->parcial_nl_counter = 0;

					}
		return true;
	} else
		cout << "line " << the_context->acum_nl_counter + 1 << "error" << endl;
	return false;
}
